package com.study.juc.atomics;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @program: juc-study
 * @author: jzhou
 * @date: 2022-08-16 17:37
 * @version: 1.0
 * @description: ABA问题演示及问题解决方案,及使用AtomicStampedReference解决该问题
 **/
public class ABADemo {
	private static AtomicInteger atomicInteger = new AtomicInteger(100);
	private static AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(100,1);

	public static void main(String[] args) {
		new Thread(()->{
			int stamp = stampedReference.getStamp();
			System.out.println(Thread.currentThread().getName() +"\t"+ "首次版本号：" + stamp);
			// 这里暂停是为了让另一个线程拿到的版本号和当前线程一样
			try { TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}
			System.out.println(stampedReference.compareAndSet(100, 101, stamp, stamp + 1) +
					"\t 2次流水号："+ stampedReference.getStamp());
			System.out.println(stampedReference.compareAndSet(101, 100, stampedReference.getStamp(),
					stampedReference.getStamp() + 1) +"\t 3次流水号："+ stampedReference.getStamp());

		},"t3").start();

		new Thread(()->{
			int stamp = stampedReference.getStamp();
			System.out.println(Thread.currentThread().getName() +"\t"+ "首次版本号：" + stamp);
			// 此处暂停是为了让t3发生 ABA 问题
			try { TimeUnit.MILLISECONDS.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
			System.out.println(stampedReference.compareAndSet(100, 2022, stamp, stamp + 1) +
					"\t"+ stampedReference.getStamp() +"\t"+ stampedReference.getReference());
		},"t4").start();
	}

	private static void abaHappen() {
		new Thread(()->{
			System.out.println(atomicInteger.compareAndSet(100, 101) +"\t"+ atomicInteger.get());
			try { TimeUnit.MILLISECONDS.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}
			System.out.println(atomicInteger.compareAndSet(101, 100) +"\t"+ atomicInteger.get());
		},"t1").start();

		new Thread(()->{
			try { TimeUnit.MILLISECONDS.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}
			System.out.println(atomicInteger.compareAndSet(100, 2022) +"\t"+ atomicInteger.get());
		},"t2").start();
	}
}
